using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

using System.ComponentModel;
using System.Collections.Generic;
using System.Web;

namespace LenninSoftware.FormEditor
{
    public abstract class BaseListItemViewer: System.Web.UI.WebControls.WebParts.WebPart  
    {


        public abstract SPWeb Web
        {
            get;
        }

        public abstract SPList List
        {
            get;
        }

        public abstract SPListItemCollection Items
        {
            get;
        }


        private bool _buttonsAtTop;
        private bool _descriptionsUnderLabels;
        private SPControlMode _controlMode = SPControlMode.New;


        public virtual SPControlMode ControlMode
        {
            get { return _controlMode; }
            set { _controlMode = value; }
        }
  
        public bool ButtonsAtTop
        {
            get { return _buttonsAtTop; }
            set { _buttonsAtTop = value; }
        }

        public bool DescriptionsUnderLabels
        {
            get { return _descriptionsUnderLabels; }
            set { _descriptionsUnderLabels = value; }
        }

        protected virtual bool CanAddAttachments
        {
            get { return !IsReadOnly; }
        }

        protected virtual bool IsReadOnly
        {
            get { return false; }
        }

        private static void AddRow(Table table, Control control)
        {
            TableCell cell = AddRowAndCell(table);
            cell.Controls.Add(control);
        }

        protected virtual void AddToolbarRow(Table table, ItemEditor itemEditor)
        {
            AddRow(table, CreateToolbar(itemEditor));
            AddRow(table, CreateEmptyImage(1, 7));
        }

        private InformationBar _infoBar;

        protected InformationBar InformationBar
        {
            get
            {
                return _infoBar;
            }
        }

        protected Control CreateInputTable(ItemEditor itemEditor)
        {
            Table table = new Table();
            table.CellPadding = 0;
            table.CellSpacing = 0;
            table.ID = "part1";
            table.Width = new Unit(100, UnitType.Percentage);

            bool hasWriteableFields;
            Control fieldsTable = CreateFieldsTable(itemEditor, out hasWriteableFields);

            _infoBar = new InformationBar();
            AddRow(table, _infoBar);

            AddRow(table, CreateEmptyImage(1, 7));

            if (ButtonsAtTop) AddRow(table, CreateTopFormButtonBar(itemEditor, hasWriteableFields));

            AddRow(table, CreateEmptyImage(1, 7));

            AddToolbarRow(table, itemEditor);

            AddRow(table, fieldsTable);
            AddRow(table, CreateEmptyImage(1, 7));

            AddRow(table, CreateBottomFormButtonBar(itemEditor, hasWriteableFields));

            return table;
        }

        private static TableCell AddRowAndCell(Table table)
        {
            TableRow row = new TableRow();
            TableCell cell = new TableCell();
            row.Cells.Add(cell);
            table.Rows.Add(row);

            return cell;
        }

        protected override void CreateChildControls()
        {

            if (DesignMode)
            {
                Controls.Clear();
                Label label = new Label();
                label.Text = "Output of controls disabled in design mode";
                Controls.Add(label);
                return;
            }

            base.CreateChildControls();

            try
            {

                Page.ClientScript.RegisterClientScriptInclude("Form", "/_layouts/1033/Form.js");
                Page.ClientScript.RegisterClientScriptInclude("SpellCheckEntirePage", "/_layouts/1033/SpellCheckEntirePage.js");


                SPList list = List;

                if (list == null) return;

                Table table = new Table();

                if (CanAddAttachments) AddRow(table, CreateAttachmentsTable(list));

                foreach (SPListItem item in Items)
                {
                    ItemEditor itemEditor = new ItemEditor(item, Web, list, SPControlMode.Display);

                    AddRow(table, CreateInputTable(itemEditor));
                }

                Controls.Add(table);

                // if (CanAddAttachments) Controls.Add(GenerateHideEmptyAttachmentsScriptControl());

                
            }
            catch (Exception ex)
            {
                Controls.Clear();
                Label label = new Label();
                label.Text = ex.ToString();
                Controls.Add(label);
            }
        }

        private static TableRow CreateEmptyRow()
        {
            TableRow row = new TableRow();
            row.Height = 1;
            row.Width = new Unit(100, UnitType.Percentage);
            row.VerticalAlign = VerticalAlign.Top;

            TableCell cell1 = new TableCell();
            cell1.CssClass = "ms-formline";
            row.Cells.Add(cell1);

            TableCell cell2 = new TableCell();
            cell2.CssClass = "ms-formline";
            row.Cells.Add(cell2);

            Image image = CreateEmptyImage();
            cell1.Controls.Add(image);
            cell2.Controls.Add(image);

            return row;
        }

        private static Image CreateEmptyImage()
        {
            return CreateEmptyImage(1, 1);
        }

        private static Image CreateEmptyImage(int width, int height)
        {
            Image image = new Image();
            image.ImageUrl = "/_layouts/images/blank.gif";
            image.Width = width;
            image.Height = height;
            return image;
        }

        protected virtual Control CreateToolbar(ItemEditor editor)
        {
            ToolBar toolbar = new ToolBar(editor);
            return toolbar;
        }

        private Table CreateAttachmentsTable(SPList list)
        {
            AttachmentUpload attachmentsUpload = new AttachmentUpload();
            attachmentsUpload.ID = "fileupload";
            attachmentsUpload.ListId = list.ID;
            attachmentsUpload.ControlMode = ControlMode;

            TableCell cell = new TableCell();
            cell.Controls.Add(attachmentsUpload);

            TableRow row = new TableRow();
            row.Cells.Add(cell);

            Table table = new Table();
            table.Rows.Add(row);

            return table;
        }

        private static SPField GetAttachmentsField(SPList list)
        {
            foreach (SPField field in list.Fields)
            {
                if (field.Type == SPFieldType.Attachments)
                {
                    return field;
                }
            }

            return null;
        }


        private Table CreateFieldsTable(ItemEditor itemEditor, out bool hasWriteableFields)
        {
            Table table = new Table();
            table.CellPadding = 0;
            table.CellSpacing = 0;
            table.Width = new Unit(100, UnitType.Percentage);

            IEnumerable<FieldToRender> fieldsToRender = EnumerateFields(itemEditor.List);
            fieldsToRender = StripNonVisibleFields(fieldsToRender);

            List<FieldToRender> fields = new List<FieldToRender>(fieldsToRender);
            hasWriteableFields = HasWriteableFields(fields);

            IEnumerable<TableRow> renderedRows = CreateFieldControlRows(itemEditor, fields);

            foreach (TableRow row in renderedRows) table.Rows.Add(row);

            //table.Rows.Add(CreateAttachmentsRow(list));

            table.Rows.Add(CreateEmptyRow());

            return table;
        }

        protected static bool HasWriteableFields(IEnumerable<FieldToRender> fields)
        {
            foreach (FieldToRender field in fields)
            {
                if (field.IsWriteable) return true;
            }

            return false;
        }

        protected virtual IEnumerable<FieldToRender> EnumerateFields(SPList list)
        {
            foreach (SPField field in list.Fields)
            {
                bool isVisible = true;
                bool isWriteable = true;

                SPFieldInfo fieldInfo = new SPFieldInfo(field);

                yield return new FieldToRender(fieldInfo, isVisible, isWriteable);
            }
        }

        private static IEnumerable<FieldToRender> StripNonVisibleFields(IEnumerable<FieldToRender> fields)
        {
            foreach (FieldToRender field in fields)
            {
                if (field.IsVisible) yield return field;
            }
        }

        private Table CreateTopFormButtonBar(ItemEditor itemEditor, bool hasWriteableFields)
        {
            return CreateFormButtonBar(itemEditor, "toolBarTbltop", hasWriteableFields);
        }

        private Table CreateBottomFormButtonBar(ItemEditor itemEditor, bool hasWriteableFields)
        {
            return CreateFormButtonBar(itemEditor, "toolBarTblbottom", hasWriteableFields);
        }

        protected virtual Table CreateFormButtonBar(ItemEditor itemEditor, string tableId, bool hasWriteableFields)
        {
            Table table = new Table();
            return table;
        }

        protected static Table CreateFormButtonBar(params Control[] controls)
        {
            Table table = new Table();
            table.CssClass = "ms-formtoolbar";
            table.CellPadding = 2;
            table.CellSpacing = 2;
            table.BorderWidth = 0;
            table.Width = new Unit(100, UnitType.Percentage);

            TableRow row = new TableRow();

            TableCell cell1 = new TableCell();
            cell1.Width = new Unit(99, UnitType.Percentage);
            cell1.CssClass = "ms-toolbar";
            cell1.Attributes.Add("nowrap", "true");

            row.Cells.Add(cell1);

            Image image = new Image();
            image.ImageUrl = "/_layouts/images/blank.gif";
            image.Width = new Unit(1);
            image.Height = new Unit(18);

            cell1.Controls.Add(image);

            table.Rows.Add(row);

            foreach (Control control in controls)
            {
                TableCell containerCell = new TableCell();
                containerCell.CssClass = "ms-toolbar";
                containerCell.Attributes.Add("nowrap", "true");

                row.Cells.Add(containerCell);

                Table containerTable = new Table();
                containerTable.CellPadding = 0;
                containerTable.CellSpacing = 0;
                containerTable.Width = new Unit(100, UnitType.Percentage);

                TableRow row1 = new TableRow();

                TableCell cell = new TableCell();
                cell.HorizontalAlign = HorizontalAlign.Right;
                cell.Width = new Unit(100, UnitType.Percentage);
                cell.Attributes.Add("nowrap", "true");

                cell.Controls.Add(control);

                row1.Cells.Add(cell);

                containerTable.Rows.Add(row1);

                containerCell.Controls.Add(containerTable);
            }

            return table;
        }

        private IEnumerable<TableRow> CreateFieldControlRows(ItemEditor itemEditor, IEnumerable<FieldToRender> fields)
        {
            foreach (FieldToRender fieldToRender in fields)
            {
               yield return CreateLabelAndControlRowForField(itemEditor, fieldToRender.Field);
            }
        }

        private List<Control> _formFields = new List<Control>();


        protected virtual IAdapterFactory AdapterFactory
        {
            get
            {
                return new AdapterFactory();
            }
        }

        private TableRow CreateLabelAndControlRowForField(ItemEditor itemEditor, FieldInfo field)
        {
            Control label = CreateFieldLabelControl(itemEditor, field);
            Control formField = CreateFieldFormControl(itemEditor, field);

            _formFields.Add(formField);

            string fieldName = field.StaticName.Replace(" ", "_");

            TableRow row = new TableRow();
            row.ID = itemEditor.List.Title + "_" + fieldName + "_Row";

            TableCell cellLabel = new TableCell();
            row.Cells.Add(cellLabel);
            cellLabel.ID = itemEditor.List.Title + "_" + fieldName + "_LabelCell";

            TableCell cellControl = new TableCell();
            row.Cells.Add(cellControl);
            cellControl.ID = itemEditor.List.Title + "_" + fieldName + "_ControlCell";

            cellLabel.Controls.Add(label);
            cellControl.Controls.Add(formField);

            if (itemEditor.ControlMode == SPControlMode.New || itemEditor.ControlMode == SPControlMode.Edit)
            {
                if (!string.IsNullOrEmpty(field.Description))
                {
                    Literal descriptionText = new Literal();
                    descriptionText.Text = "<br><span style=\"font-weight: normal;\">" +
                                           HttpUtility.HtmlEncode(field.Description) + "</span>";

                    if (DescriptionsUnderLabels)
                    {
                        descriptionText.Text = "<br/>" + descriptionText.Text;
                        cellLabel.Controls.Add(descriptionText);
                    }
                    else
                    {
                        cellControl.Controls.Add(descriptionText);
                    }
                }
            }

            cellLabel.CssClass = "ms-formlabel";
            cellControl.CssClass = "ms-formbody";

            return row;
        }

        protected abstract Nullable<int> ItemID
        {
            get;
        }   


        private Control CreateFieldFormControl(ItemEditor itemEditor, FieldInfo field)
        {
            FormControl control = new FormControl(field, itemEditor, AdapterFactory, itemEditor.ControlMode);
            return control;
        }

        private Control CreateFieldLabelControl(ItemEditor itemEditor, FieldInfo field)
        {
            FieldLabel label = new FieldLabel(field, itemEditor);
            return label;
        }

        protected bool IsPostBack
        {
            get
            {
                if (ViewState["IsPostBack"] == null)
                    return false;

                return (bool)ViewState["IsPostBack"];
            }
        }

        protected void SetIsPostBack()
        {
            ViewState["IsPostBack"] = true;
        }
		

        protected void LoadData()
        {
            foreach (FormControl control in _formFields)
            {
                control.LoadData();
            }
        }

        protected void ResetData()
        {
            FormControl firstControl;

            foreach (FormControl control in _formFields)
            {
                control.Reset();
            }

            if (_formFields.Count > 0)
            {
                firstControl = (FormControl)_formFields[0];
                firstControl.Focus();
            }


        }


        protected override void OnPreRender(EventArgs e)
        {
            if (List == null)
                return;

            if (InformationBar !=null )
                InformationBar.Message = Message;            
        }

        protected virtual void BeforeSave()
        {

        }

        protected PropertyBag SaveData(out bool missingRequiredFields)
        {
            missingRequiredFields = false;

            PropertyBag data = new PropertyBag();

            foreach (FormControl control in _formFields)
            {
                if (control.IsEmptyAndRequired())
                {
                    missingRequiredFields = true;
                    break;
                }
            }

            if (missingRequiredFields)
                return data;

            foreach (FormControl control in _formFields)
            {
                control.Save(data);
            }

            return data;
            
        }

        protected override void OnLoad(EventArgs e)
        {
            EnsureChildControls();

            if (!IsPostBack)
            {
                LoadData();
                SetIsPostBack();
            }
        }

        protected void Reset()
        {
            Controls.Clear();
            CreateChildControls();
            
            LoadData();
            SetIsPostBack();
        }

        protected void LoadDefaults(PropertyBag defaults)
        {
            FormControl firstControl;

            foreach (FormControl control in _formFields)
            {
                control.LoadDefaults(defaults);
            }

            if (_formFields.Count > 0)
            {
                firstControl = (FormControl)_formFields[0];
                firstControl.Focus();
            }

        }


        private string _message;

        public string Message
        {
            get
            {
                return _message;
            }
            set
            {
                _message = value;
            }
        }

    }
}
